--======================================================================
--（c）copyright 2015 175game.com All Rights Reserved
--======================================================================
-- anthor: lorry
-- modifier: hy
-- filename: actor.lua
-- descrip: 演员基类，一般来说，场景里面所有可以看到的物体都可以此类作为基类
--======================================================================

local CObjectBase = Import("logic/object/base_object").CObjectBase
local CommonEnum = Import("logic/base/common_enum").Enum
local CommonUtil = Import("logic/util/common_util").Util
local Tool = Import("logic/common/tool").CTool
local CUIFollowTargetWidget = Import("logic/ui/common/ui_follow_target_widget").CUIFollowTargetWidget
local CUIFollowTargetWidget3d = Import("logic/ui/common/ui_follow_target_widget_3d").CUIFollowTargetWidget3d
local CBubbleChat = Import("logic/ui/chat/bubble_chat").CBubbleChat
local ALL_RES_ID = Import("logic/config/info_res_id").resid
local CFightStatusData = Import("logic/data/fight_status_data").CFightStatusData
local ModAI = Import("logic/modules/ai/ai_base")
local AI_OPPORTUNITY = ModAI.AI_OPPORTUNITY
local info_equip_exchange_item = Import("logic/config/info_equip_exchange_item").equip_exchange_item_info

local math = math

CActor = class(CObjectBase)
CActor.__name = "CActor"

CActor.Init = function (self, args)
	CObjectBase.Init(self)
	self._type = nil							-- 对象类型
	self._data = nil							-- 对象逻辑数据
	self._aniState = CommonEnum.STATE_STAND		-- 对象当前动画状态
	self._defaultAniState = CommonEnum.STATE_STAND		-- 对象默认动画状态
	self._area = CommonEnum.AREA_GROUND			-- 对象所在域
	self._mainPrefabPath = nil			 		-- 主模型的预制件路径，可能会没有
	self._subPrefabPaths = nil			 		-- 部件模型的预制件路径数组，可能会没有
	self._uiPrefabPath = nil					-- ui的预制件路径，可能会没有
	self._bodyEffectPath = nil 					--模型的常驻特效路径，可能会没有
	self._ui = nil								-- ui
	self._uiFollowTargetObj = nil				-- CUIFollowTargetWidget的实例化对象
	self._searchToAction = nil					-- 寻路动作
	self._animationAction = nil					-- 动画动作
	self._moveToAction = nil					-- 移动动作
	self._isShow = true 						-- U3D的真实对象的显示状态
	self._isUIShow = true 						-- UI的真实对象的显示状态
	self._guaHp = nil							-- 角色头顶挂点
	self._speed = 5								-- 真实移动速度
	self._speedBak = 5							-- 移动速度样本
	self._speedAnim = 1							-- 真实动画速度
	self._status = {}							-- 状态
	-- self._stashStatus = {}						-- 有状态特效但不显示出来的状态
	self._effectObjList = {}					-- 特效Obj列表
	self._permanentEffectGos = {}				--常驻特效Obj列表
	self._ai = {}								-- AI列表
	self._runningAI = {}						-- 运行的AI列表
	self._aiData = {}							-- AI数据
	self._curWorldPos = Vector3.New(0, 0, 0)	-- 当前世界坐标
	self._preWorldPos = Vector3.New(0, 0, 0)	-- 前一个世界坐标
	self._posChangeFlag = 0.2					-- 判断位置变化边界值
	self._id = 0								-- id
	self._resid = nil							-- 造型资源id
	self._equipTypes = nil						-- 装备类型id数组
	self._isUsePack = false						-- 是否使用锦囊
	self._isHero = false						-- 是否当前玩家
	self._isDie = false							-- 是否已经死亡
	self._isShowModel = true					-- 是否显示模型
	self._orgId = nil							-- 帮派id,进入帮战才有
	self._isNeedUi = false						-- 是否需要Ui，街区场景不需要Ui

	self._effectLastTimer = {}
	self._effectDelayTimer = {}

	self._data = args or {}

	self._resid = self._data.resid or 0
	self._equipPartObjList = {}
	self._delayEquipPartList = {}

	self._owner = nil
	-- 跟随最大距离
	self._maxDist = 2

	if args then
		table.merge(self._data, args.data)

		self._mainPrefabPath = args.mainPrefabPath
		self._subPrefabPaths = args.subPrefabPaths
		self._uiPrefabPath = args.uiPrefabPath

		if args.resid then
			self._resid = args.resid
			local resInfo = ALL_RES_ID[args.resid]

			if resInfo then
				--默认部位
				self._mainPrefabPath = resInfo.prefab_path
				self._subPrefabPaths = self:GetPartPaths(resInfo)

				if resInfo.effect_path and resInfo.effect_path ~= '' then
					self._bodyEffectPath = resInfo.effect_path
				end
			end
		end

		self._equipTypes = args.equipTypes

		self._finishCB = args.finishCB
	end

	self._isNeedUi = self._data["isNeedUi"]

	local gameObjectInfo = gGame:GetGameObjectMgr():NewGameObjectInfo()
	self._gameobjectUID = gameObjectInfo._id	-- 渲染对象GameObject的信息id
	if self._data.useAsyncLoad ~= nil then
		self._useAsyncLoad = self._data.useAsyncLoad
	else
		self._useAsyncLoad = true
	end

	self._id = self._data.id or 0
	local heroData = gGame:GetDataMgr():GetHeroData()
	if heroData:GetId() == self._id then
		self._isHero = true
	end
	gameObjectInfo:SetName(self._id)

	if self._data.defaultAniState then
		self._defaultAniState = self._data.defaultAniState
	else
		local baseResInfo = ALL_RES_ID[self._resid]
		if baseResInfo then
			self._defaultAniState = baseResInfo['default_ani_state'] --如果是数字转为整型，赋值状态，如果是字符串，赋值触发器
		end
	end

	self:InitListener()
	--local beforeT = UnityEngine.Time.realtimeSinceStartup
	self:InitModel(self._mainPrefabPath, self._data.gameObject)
	self:InitPart(self._subPrefabPaths)
	self:InitEquip(self._equipTypes)
	--local afterT = UnityEngine.Time.realtimeSinceStartup
	--print(string.format("-------Actor id=%s InitModel --------- 耗时=%.6f", self._id, afterT - beforeT))
	--self:InitColor()
	self:InitComponent()
	self:InitAI()

	self:SetLayer("Actor")
end

-- 初始化模型
CActor.InitModel = function (self, mainPrefabPath, gameObject)
	local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)
	self._mainPrefabPath = mainPrefabPath
	if mainPrefabPath then
		if self._useAsyncLoad then
			local objOptimized = string.find(mainPrefabPath, "Assets/res/Prefabs/char/") and true
			objOptimized = Tool.CanObjOptimized(mainPrefabPath) and objOptimized
			gameObjectInfo:InitGameObjectAsync(mainPrefabPath, nil, objOptimized)
		else
			gameObjectInfo:InitGameObject(mainPrefabPath)
		end
	end

	if gameObjectInfo:IsGoValid() then
		self._guaHp = gameObjectInfo._gameObject.transform:Find("gua_hp")
		if not self._guaHp then
			self._guaHp = gameObjectInfo._gameObject.transform
		end

		if self._bodyEffectPath then
			local effectGo = self:CreateEffectGameObject("gua_effect_foot", self._bodyEffectPath, true)
			table.insert(self._permanentEffectGos, effectGo)
		end

	elseif gameObject then
		gameObjectInfo:SetGameObject(gameObject)
		--self._guaHp = gameObjectInfo._gameObject.transform
		self._guaHp = gameObjectInfo._gameObject.transform:Find("gua_hp")
		if not self._guaHp then
			self._guaHp = gameObjectInfo._gameObject.transform
		end
	else
		gameObjectInfo:SetGameObject(GameObject.New())
		self._guaHp = gameObjectInfo._gameObject.transform
	end

	local clientX = 0
	local clientY = 0
	local clientZ = 0
	if self._data.x and self._data.y then
		clientX = CommonUtil.ServerXToClientX(self._data.x)
		clientZ = CommonUtil.ServerYToClientZ(self._data.y)
	end
	if self._data.height then
		clientY = self._data.height / CommonEnum.DEFAULT_SERVER_HEIGHT_TIMES
	else
		local hasRayCast, rayCastHeight = CommonUtil.GetServerHeightByRayCast(clientX, clientZ, self._area)
		if hasRayCast then
			clientY = rayCastHeight
			self._data.height = clientY * CommonEnum.DEFAULT_SERVER_HEIGHT_TIMES
		end
	end

	self._curWorldPos = Vector3.New(clientX, clientY, clientZ)
	self._preWorldPos = self._curWorldPos
	self:SetPosition(self._curWorldPos, true)
	self._originRotation = gameObjectInfo._gameObject.transform.rotation
end

-- 初始化部位
--subPrefabPaths ： prefab路径数组
CActor.InitPart = function (self, subPrefabPaths)
	self._subPrefabPaths = subPrefabPaths
	local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)
	if not gameObjectInfo then
		local resid = self._resid or 0
		warn("InitPart Fail, Actor GameObjectInfo nil, resid:"..resid)
		print_stack()
		return
	end
	if self._useAsyncLoad then
		gameObjectInfo:InitPartAsync(self._subPrefabPaths)
	else
		gameObjectInfo:InitPart(self._subPrefabPaths)
	end
end

-- 初始化装备
--equipTypes ： equipTypes装备类型id数组
CActor.InitEquip = function (self, equipTypes)
	self._equipTypes = equipTypes
	if not equipTypes then return end
	local equipBase = nil
	local partName = nil
	local resInfo = nil
	if self._resid then
		resInfo = ALL_RES_ID[self._resid]
	end
	local partPrefabPaths = nil
	if resInfo then
		--默认装备
		partPrefabPaths = {[CommonEnum.PART_7_HEAD] = resInfo.head_prefab_path,
		[CommonEnum.PART_3_BODY] = resInfo.body_prefab_path,
		[CommonEnum.PART_1_WEAPON] = resInfo.weapon_prefab_path,
		[CommonEnum.PART_8_HAIR] = resInfo.hair_prefab_path,}
	else
		partPrefabPaths = {}
	end

	if not resInfo then
		warn_stack("造型总表.xls 缺少造型配置, Id:", self._resid)
		return
	end

	local sceneData = gGame:GetDataMgr():GetSceneData()
	if sceneData:GetSceneIsModern() and (not gGame:GetSceneMgr():isFightScene()) then
		--如果是现代场景武器不影响外形,如果是现代的战斗场景要换武器
		equipTypes = {}
	end

	for k,v in ipairs(equipTypes) do
		equipBase = info_equip_exchange_item[v]
		--只有变武器
		if equipBase and CommonEnum.EquipLocateToPartName[equipBase.locate] == CommonEnum.PART_1_WEAPON then
			partName = CommonEnum.EquipLocateToPartName[equipBase.locate]

			local equipAsset = equipBase.Sname
			local sex = resInfo.gender
			local school = resInfo.school or -1
			assert(sex >= 0 and sex <= 2, string.format("resInfo性别有问题呦, sex :  %d ", sex))
			local equipAssetKey = string.format("model%d%d", school, sex)
			equipAsset = equipBase[equipAssetKey] or ""
			if partName and equipAsset ~= "" then
				partPrefabPaths[partName] = string.format("Assets/res/Prefabs/avatar/%s", equipAsset)
			end
		end
	end

	self:InitPart(partPrefabPaths)
end

CActor.InitColor = function(self)
	local resId = self._resid

	if resId ~= 0 then
		local resInfo = ALL_RES_ID[resId]

		if resInfo == nil then
			Logger.error("该资源不存在 ：" .. resId)
			return
		end

		-- 只对将要合成的灵兽进行染色
		if resInfo.is_merge_summon == 1 then
			local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)
			local mesh_root = gameObjectInfo._gameObject.transform:Find("mesh_root")
			local summonMergeMgr = gGame:GetSummonMergeMgr()

			summonMergeMgr:SetSummonColor(mesh_root, summonMergeMgr:ResolveSummonColor(resInfo.color_area_1), "R")
			summonMergeMgr:SetSummonColor(mesh_root, summonMergeMgr:ResolveSummonColor(resInfo.color_area_2), "G")
			summonMergeMgr:SetSummonColor(mesh_root, summonMergeMgr:ResolveSummonColor(resInfo.color_area_3), "B")
		end
	end

end

-- 初始化组件
CActor.InitComponent = function (self)

end

-- -- 初始化ui
CActor.InitUI = function (self)
	if not self._isNeedUi then return end

	local hasUi = false
	local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)
	if self._uiPrefabPath and gameObjectInfo:IsGoValid() then
		hasUi = true
		self._ui = Tool.Instantiate(self._uiPrefabPath)
		self._ui:SetActive(self._isShow)

		local nameObj = Tool.GetChildRecursive(self._ui, "Name")
		self._ui._nameText = nameObj:GetComponent("UnityEngine.UI.Text")
		self._ui._nameText.text = ""

		local rewardObj = Tool.GetChildRecursive(self._ui, "Nego_ImgReward")
		if rewardObj then
			self._ui._rewardObj = rewardObj
			self._ui._rewardObj:SetActive(false)
		end

		local leaderIconObj = Tool.GetChildRecursive(self._ui, "Nego_ImgLeader")
		if leaderIconObj then
			self._ui._leaderIconObj = leaderIconObj
			self._ui._leaderIconObj:SetActive(false)
		end
	end

	if hasUi then
		local uiContainerGo = self:GetUiFollowTargetObj():GetRootObj()
		self._ui.transform:SetParent(uiContainerGo.transform, false)
	end
end

-- 初始化事件
CActor.InitListener = function (self)
	local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)
	gameObjectInfo._onMainInitFinish = function(isAsync) self:HandlerMainInitFinish(isAsync) end
	gameObjectInfo._onPartInitFinish = function(isAsync)
		self:InitColor()
		self:HandlerPartInitFinish(isAsync)
	end
	gameObjectInfo._onGoInitFinish = function(isAsync)
		self:HandlerGoInitFinish(isAsync)

		if self._finishCB and type(self._finishCB) == "function"  then
			self._finishCB(self)
		end
	end
end

--更换造型（变身）
--新造型go会挂在和旧造型go相同的父节点下面，且位置等信息会“copy”旧造型go的过来
--会把旧造型go的第一层所有子节点（除了骨骼根节点Bip001、mesh_root节点、带有skinMeshRenderer或者MeshRenderer的子节点）都重新挂到新造型go上，
--且会按照新造型go上对应名字节点的位置等信息“copy”给旧造型对应子节点
-- toSecondForm 表示是否转换到第二形态
CActor.ResetModel = function(self, resId, equipTypes, toSecondForm)
	if not resId then return end
	-- if self._resid ~= resId or toSecondForm then
		-- 删除上个形态添加的挂件
		self:ClearItemObjList()
		self._toSecondForm = toSecondForm

		local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)
		local parent = gameObjectInfo._gameObject.transform.parent
		local localPosition = gameObjectInfo._gameObject.transform.localPosition
		local localRotation = gameObjectInfo._gameObject.transform.localRotation
		local localScale = gameObjectInfo._gameObject.transform.localScale

		local animator = gameObjectInfo._gameObject:GetComponent("Animator")
		local animatorStateInfo = animator:GetCurrentAnimatorStateInfo(0)
		self._playingStateNameHash = animatorStateInfo.shortNameHash
		self._playingStateTime = animatorStateInfo.normalizedTime

		local childTrans = {}
		local childCount = gameObjectInfo._gameObject.transform.childCount
		for i = 0, childCount - 1 do
			local childTran = gameObjectInfo._gameObject.transform:GetChild(i)
			if childTran.name ~= "mesh_root" and (not string.find(childTran.name, "Bip")) then
				local skinMeshRendererC = UtilCommon.GetComponent(childTran.gameObject, "SkinnedMeshRenderer")
				local meshRendererC = UtilCommon.GetComponent(childTran.gameObject, "MeshRenderer")
				if not skinMeshRendererC and not meshRendererC then
					table.insert(childTrans, {transform = childTran, isActive = childTran.gameObject.activeSelf})
				end
			end
		end
		for k,v in ipairs(childTrans) do
			-- v.transform.gameObject:SetActive(false)
			v.transform:SetParent(nil, false)
		end

		self._resid = resId
		local resInfo = ALL_RES_ID[resId]
		local mainPrefabPath = nil
		if resInfo then
			mainPrefabPath = resInfo['prefab_path']
			if self._toSecondForm then mainPrefabPath = resInfo['second_prefab_path'] end
		end

		self:InitModel(mainPrefabPath, nil)

		if not equipTypes or #equipTypes == 0 then
			self:InitPart(self:GetPartPaths(resInfo))
		else
			self:InitEquip(equipTypes)
		end

		for k,v in ipairs(childTrans) do
			local sameNameChildTran = gameObjectInfo._gameObject.transform:Find(v.transform.name)
			if sameNameChildTran then
				v.transform.localPosition = sameNameChildTran.localPosition
				v.transform.localEulerAngles = sameNameChildTran.localEulerAngles
				v.transform.localScale = sameNameChildTran.localScale
				local childCount = sameNameChildTran.childCount
				local childTranList = {}
				for i = 0, childCount - 1 do
					local childTran = sameNameChildTran:GetChild(i)
					local subSameNameChildTran = v.transform:Find(childTran.name)
					if subSameNameChildTran then
						-- GameObject.Destroy(subSameNameChildTran.gameObject)
					end
					-- childTran:SetParent(v.transform, false)
					table.insert(childTranList, childTran)
				end

				for _, trans in pairs(childTranList) do
					trans:SetParent(v.transform, false)
				end
				-- GameObject.Destroy(sameNameChildTran.gameObject)
			end
			v.transform:SetParent(gameObjectInfo._gameObject.transform, false)
			-- v.transform.gameObject:SetActive(v.isActive)
		end
		childTrans = nil
		if parent then
			gameObjectInfo._gameObject.transform.parent = parent
		end
		gameObjectInfo._gameObject.transform.localPosition = localPosition
		gameObjectInfo._gameObject.transform.localRotation = localRotation
		gameObjectInfo._gameObject.transform.localScale = localScale
	-- end
end

CActor.HandlerMainInitFinish = function (self, isAsync)
	local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)
	local go = gameObjectInfo._gameObject

	-- 变身后接着播放变身前的动画
	if self._playingStateTime and self._playingStateNameHash then
		local animator = go:GetComponent("Animator")
		animator:Play(self._playingStateNameHash, 0, self._playingStateTime)
		self._playingStateTime = nil
		self._playingStateNameHash = nil
	end

	-- 变身后添加部件，防止变身过程中部件被销毁
	for _, equipPartInfo in pairs(self._delayEquipPartList) do
		self:AddEquipPartObj(equipPartInfo["equipPartPath"], equipPartInfo["plugName"], equipPartInfo["pos"], equipPartInfo["rot"], equipPartInfo["scale"])
	end
	self._delayEquipPartList = {}

	local numState = tonumber(self._defaultAniState)
	if numState and numState == CommonEnum.STATE_DIE then
		self:DieInstant()
	elseif self._aniState ~= CommonEnum.STATE_STAND then
		self:SetAniState(self._aniState)
	end
end

CActor.HandlerPartInitFinish = function (self, isAsync)

end

CActor.HandlerGoInitFinish = function (self, isAsync)
	if self._data.playAction then
		local playAction = self._data.playAction
		self:PlayAction(playAction.action, playAction.cnt, playAction.pauseFlg, playAction.playTime)
	end

	self:InitUI()
end

-- 初始化AI
CActor.InitAI = function(self)

end

CActor.GetUiFollowTargetObj = function(self)
	if not self._uiFollowTargetObj then
		self._uiFollowTargetObj = CUIFollowTargetWidget3d:New("Assets/res/Prefabs/ui/head/PnlActorHeadContainer.prefab", self:GetGameObject())
		self._uiFollowTargetObj:SetNoScale(true)
	end
	return self._uiFollowTargetObj
end

CActor.GetDelayEquipPartList = function(self)
	return self._delayEquipPartList
end

-- 合成所需部件的路径
CActor.GetPartPaths = function(self, resInfo)
	if not resInfo then return end
	local subPrefabPaths = {}

	-- 是否为将要合成的灵兽
	-- 灵兽合成规则以变，is_merge_summon == 1已经没有意义
	if resInfo.is_merge_summon == 0 then
		if self._toSecondForm then
			subPrefabPaths = {
				[CommonEnum.PART_7_HEAD] = resInfo.second_head_prefab_path,
				[CommonEnum.PART_3_BODY] = resInfo.second_body_prefab_path,
				[CommonEnum.PART_1_WEAPON] = resInfo.second_weapon_prefab_path,
				[CommonEnum.PART_8_HAIR] = resInfo.second_hair_prefab_path,
			}
		else
			subPrefabPaths = {
				[CommonEnum.PART_7_HEAD] = resInfo.head_prefab_path,
				[CommonEnum.PART_3_BODY] = resInfo.body_prefab_path,
				[CommonEnum.PART_1_WEAPON] = resInfo.weapon_prefab_path,
				[CommonEnum.PART_8_HAIR] = resInfo.hair_prefab_path,
			}
		end
	end

	return subPrefabPaths
end

-- 添加部件,如肩甲，翅膀
CActor.AddEquipPartObj = function(self, equipPartPath, plugName, pos, rot, scale, delay)
	-- 如果要在变身过程中添加部件，要等变身完
	if delay then
		local equipInfo = {
			["equipPartPath"] = equipPartPath,
			["plugName"] = plugName,
			["pos"] = pos,
			["rot"] = rot,
			["scale"] = scale,
		}
		table.insert(self._delayEquipPartList, equipInfo)
	else
		local equipPartObj = Tool.Instantiate(equipPartPath)
		if not equipPartObj then
			return
		end

		local charObj = self:GetGameObject()
		local goPlug = Tool.GetChildRecursive(charObj, plugName)

		if tolua.isnull(goPlug) then
			goPlug = charObj
		end

		if goPlug then
			equipPartObj.transform:SetParent(goPlug.transform, false)
			equipPartObj.transform.localPosition = pos
			equipPartObj.transform.localScale = scale
			equipPartObj.transform.localEulerAngles = rot
		end

		table.insert(self._equipPartObjList, equipPartObj)
	end
end

CActor.ClearItemObjList = function(self)
	for _, obj in pairs(self._equipPartObjList) do
		GameObject.Destroy(obj)
	end
	self._equipPartObjList = {}
end

-- 添加特效
-- effectPath:特效路径, scale：1000为一倍, delayTime：延迟播放时间, lastTime：持续时间, isloop：是否循环播放, plugName：特效挂点（nil默认为角色模型原点）
CActor.AddEffect = function(self, effectPath, scale, delayTime, lastTime, isloop, plugName, finishCB)

	effectPath = "Assets/res/Effects/"..tostring(effectPath)..".prefab"
	if lastTime <= 0 then lastTime = 1 end -- 必须大于0

	if type(finishCB) ~= "function" then
		finishCB = function() end
	end

	delayTime = delayTime or 0
	scale = scale or 1000

	local function CreateEffect()
		local charObj = self:GetGameObject()

		if tolua.isnull(charObj) then
			return
		end

		local goPlug

		if plugName then
			goPlug = Tool.GetChildRecursive(charObj, plugName)
		end

		if tolua.isnull(goPlug) then
			goPlug = charObj
		end

		local effectObj = self:AddMyManagerEffect(effectPath)
		effectObj.transform.position = goPlug.transform.position
		effectObj.transform:SetParent(goPlug.transform)
		effectObj.transform.localScale = Vector3.New(scale/1000, scale/1000, scale/1000)
		effectObj.gameObject:SetActive(false)
		effectObj.gameObject:SetActive(true)

		Tool.PlayParticleEffect(effectObj)

		self:ReleaseEffectLastTimer(effectPath)

		local timeDestoryCom = effectObj:GetComponent("UITimeDestory")
		if timeDestoryCom ~= nil then
			if isloop then
				GameObject.Destroy(timeDestoryCom)
				self._effectLastTimer[effectPath] = gGame:GetTimeManager():SetTimeOut(lastTime, function()
					self:ReleaseEffectLastTimer(effectPath)
					finishCB()
				end)
			else
				timeDestoryCom:Reset()
				timeDestoryCom.Time = lastTime or timeDestoryCom.Time
				timeDestoryCom.DestoryDelegate = LuaHelper.VoidDelegate(finishCB)
			end
		elseif type(lastTime) == "number" then
			self._effectLastTimer[effectPath] = gGame:GetTimeManager():SetTimeOut(lastTime, function()
				self:ReleaseEffectLastTimer(effectPath)
				finishCB()
			end)
		end
	end

	if delayTime > 0 then
		self:ReleaseEffectDelayTimer(effectPath)

		self._effectDelayTimer[effectPath] = gGame:GetTimeManager():SetTimeOut(delayTime, function()
			self:ReleaseEffectDelayTimer(effectPath)
			CreateEffect()
		end)
	else
		CreateEffect()
	end
end

CActor.RemoveEffect = function(self, effectPath)
	local effectPath = "Assets/res/Effects/"..tostring(effectPath)..".prefab"
	self:DeleteMyManagerEffect(effectPath)
end

CActor.AddMyManagerEffect = function(self, effectPath, plugName)
	local effectObj = self._effectObjList[effectPath]
	if IsNull(effectObj) then
		effectObj = Tool.Instantiate(effectPath)
		self._effectObjList[effectPath] = effectObj
	end
	if IsNull(effectObj) then return end
	local parentTr
	if plugName then
		local goPlug = self:GetGameObject().transform:Find(plugName)
		if not IsNull(goPlug) then
			parentTr = goPlug.transform
		end
	else
		local charObj = self:GetGameObject()
		parentTr = charObj.transform
	end
	if not IsNull(parentTr) then
		effectObj.transform:SetParent(parentTr, false)
	end

	return effectObj
end

CActor.DeleteMyManagerEffect = function(self, effectPath)
	local obj = self._effectObjList[effectPath]
	if not tolua.isnull(obj) then
		GameObject.Destroy(obj)
	end
	self._effectObjList[effectPath] = nil
end

CActor.ReleaseAllObjEffect = function(self)
	for key, obj in pairs(self._effectObjList) do
		if not tolua.isnull(obj) then
			GameObject.Destroy(obj)
		end
	end
	self._effectObjList = {}
end

--使用锦囊的状态设定
CActor.SetUsePackStatus = function(self, status)
	self._isUsePack = status
end

--获取锦囊的状态设定
CActor.GetUsePackStatus = function(self)
	return self._isUsePack
end

-- 运行action动作
CActor.RunAction = function(self, action)
	local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)
	if gameObjectInfo then
		if not gameObjectInfo:IsGoValid() then return end
		gGame:GetActionMgr():AddAction(gameObjectInfo._gameObject, action)
	end
	return action
end

-- 停止action动作
CActor.StopAction = function(self, action)
	if not action then return end
	gGame:GetActionMgr():RemoveAction(action)
end

-- 停止所有action动作
CActor.StopAllAction = function(self)
	local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)

	if gameObjectInfo and gameObjectInfo:IsGoValid() then
		gGame:GetActionMgr():RemoveAllActionFromTarget(gameObjectInfo._gameObject)
	end
end

-- 暂停所有action动作
CActor.PauseAllAction = function(self)
	local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)

	if gameObjectInfo and gameObjectInfo:IsGoValid() then
		gGame:GetActionMgr():PauseAllActionFromTarget(gameObjectInfo._gameObject)
	end
end

-- 恢复所有action动作
CActor.ResumeAllAction = function(self)
	local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)
	if not gameObjectInfo:IsGoValid() then return end
	gGame:GetActionMgr():ResumeAllActionFromTarget(gameObjectInfo._gameObject)
end

CActor.SearchToPos = function(self, pos, stoppingDistance, callBack, needSmooth)
	stoppingDistance = stoppingDistance or 0
	if needSmooth == nil then
		needSmooth = false
	end

	self:StopAction(self._searchToAction)

	self._searchToAction = SearchToAction.Create()
	self._searchToAction:SetArgs(pos, self._speed, stoppingDistance, function()
		if gGame:GetLoadingMgr():IsOpen() then
			return -- 解决CActor.SearchToPos中的回调
		end
		self:Idle()
		self:OnStopSearch()
		if type(callBack) == "function" then
			callBack()
		end
		self._searchToAction = nil
	end, function()
		self:OnStartSearch()
	end, needSmooth)
	self:RunAction(self._searchToAction)
end

-- 可以寻路到目标点
CActor.CanSearchToPos = function(self, pos)
	local canSearchToPos = false

	local go = self:GetGameObject()
	canSearchToPos = SearchToAction.CanSearchToPos(go, pos)

	return canSearchToPos
end

-- 寻路到目标go
CActor.SearchToTarget = function(self, target, stoppingDistance, callBack)
	if not target then return end
	self:SearchToPos(target.transform.position, stoppingDistance, callBack)
end

CActor.GetPathPoints = function(self)
	if not self._searchToAction then return end
	return self._searchToAction:GetPathPoints()
end

-- 停止寻路
CActor.StopSearch = function(self)
	self:StopAction(self._searchToAction)

	self._searchToAction = SearchToAction.Create()
	self._searchToAction:SetArgs(function()
		self:Idle()
		self:OnStopSearch()
		self._searchToAction = nil
	end)
	self:RunAction(self._searchToAction)
end

-- 开始寻路回调
CActor.OnStartSearch = function(self)

end

-- 停止寻路回调
CActor.OnStopSearch = function(self)
	if type(self._stopSearchCb) == "function" then
		self._stopSearchCb()
	end
end

-- 设置停止寻路回调函数
CActor.SetStopSearchCB = function(self, func)
	self._stopSearchCb = func
end

-- 设置速度
CActor.SetSpeed = function (self, percent)
	self._speed = self._speedBak * percent
	self._speedAnim = percent
end

-- 移动到目标位置
CActor.MoveToPos = function(self, pos, speed, stoppingDistance, callBack)
	if self._moveToAction then
		self:StopAction(self._moveToAction)
		self._moveToAction = nil
	end
	stoppingDistance = stoppingDistance or 0
	self._moveToAction = MoveToAction.Create()
	self._moveToAction:SetArgs(pos, true, function()
		if callBack ~= nil then
			callBack()
		end
	end)

	self._moveToAction:SetDestroyCallBackFunc(function()
		self._moveToAction = nil
	end)

	self._moveToAction:SetSpeed(speed)
	self._moveToAction:SetStopDist(stoppingDistance)
	self:RunAction(self._moveToAction)
end

--播放角色动画
CActor.PlayAction = function(self, action, cnt, pauseFlg, playTime)
	if action == "flyUp" then
		if self._mount then
			self._mount:FlyUp()
		end
		return
	end
	if action == "flyDown" then
		if self._mount then
			self._mount:FlyDown()
		end
		return
	end
	local isLoop = false
	if not cnt or cnt ~= 1 then
		isLoop = true
	else
		isLoop = false
	end
	self:PlayAnimation(action, isLoop)
	-- if playTime < 1 then
	-- 	if cnt < 1 then
	-- 		self:PlayAnimation(action, true)
	-- 	else
	-- 		self:PlayAnimationByLoopNum(action, cnt)
	-- 	end
	-- else
	-- 	self:PlayAnimationByFrameNum(action, playTime)
	-- end
end

-- 位置改变回调
CActor.OnPosChangeCallBack = function(self)

end

-- 播放Animation动画
CActor.PlayAnimation = function(self, ani, isLoop, callBack)
	local animatorStateValue = CommonUtil.GetAnimatorStateValue(ani)
	if not animatorStateValue then
		if callBack ~= nil then
			callBack()
		end
		return
	end
	if isLoop == nil then
		isLoop = true
	end

	if self._animationAction then
		self:StopAction(self._animationAction)
		self._animationAction = nil
	end

	self._animationAction = AnimatorAction.Create()
	if callBack ~= nil then
		self._animationAction:SetArgs(animatorStateValue, CommonEnum.ANIMATOR_CONDITION_NAME, isLoop, callBack)
	else
		self._animationAction:SetArgs(animatorStateValue, CommonEnum.ANIMATOR_CONDITION_NAME, isLoop)
	end

	self._animationAction:SetDestroyCallBackFunc(function()
		self._animationAction = nil
	end)

	self:RunAction(self._animationAction)
end

-- 播放Animation动画（通过设置循环次数）
CActor.PlayAnimationByLoopNum = function(self, ani, loopNum, callBack)
	--todo: 目前正在把Animation换成Animator，这里面的逻辑由于是用Animation写的，先屏蔽
	-- if self._animationAction then
	-- 	self:StopAction(self._animationAction)
	-- 	self._animationAction = nil
	-- end

	-- self._animationAction = AnimatorAction.Create()
	-- if callBack ~= nil then
	-- 	self._animationAction:SetArgs(ani, loopNum, callBack)
	-- else
	-- 	self._animationAction:SetArgs(ani, loopNum)
	-- end

	-- self:RunAction(self._animationAction)
end

-- 播放Animation动画（通过设置动画帧数）
CActor.PlayAnimationByFrameNum = function(self, ani, frameNum, callBack)
	--todo: 目前正在把Animation换成Animator，这里面的逻辑由于是用Animation写的，先屏蔽
	-- if self._animationAction then
	-- 	self:StopAction(self._animationAction)
	-- 	self._animationAction = nil
	-- end

	-- self._animationAction = AnimatorAction.Create()
	-- if callBack ~= nil then
	-- 	self._animationAction:SetArgs(frameNum, ani, callBack)
	-- else
	-- 	self._animationAction:SetArgs(frameNum, ani)
	-- end

	-- self:RunAction(self._animationAction)
end

-- 停止播放Animation动画
CActor.StopAnimation = function(self)
	if self._animationAction then
		self:StopAction(self._animationAction)
		self._animationAction = nil
	end

	self._animationAction = AnimatorAction.Create()
	self._animationAction:SetArgs(function()

	end)

	self._animationAction:SetDestroyCallBackFunc(function()
		self._animationAction = nil
	end)

	self:RunAction(self._animationAction)
end

--停在Animator动画某一帧（设置Animator的state名字）
--framePercent：0-1，例如0.5表示停在stateName对应的动画中间那一帧
CActor.StopAnimationByFramePercent = function (self, stateName, framePercent)
	-- if not stateName then
	-- 	return
	-- end
	-- framePercent = framePercent or 0

	-- if self._animationAction then
	-- 	self:StopAction(self._animationAction)
	-- 	self._animationAction = nil
	-- end

	-- self._animationAction = AnimatorAction.Create()
	-- self._animationAction:SetArgs(stateName, framePercent)

	-- self:RunAction(self._animationAction)
end

-- 选中
CActor.Select = function(self)

end

-- 反选
CActor.UnSelect = function(self)

end

--需要响应该事件的话就return true，否则return false
CActor.OnFingerDown = function(self)
	return false
end

-- 是否显示
CActor.IsShow = function(self)
	return self._isShow
end



-- 只切换模型
CActor.ShowModel = function(self, isShow)
	self._isShowModel = isShow
	local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)
	local targetGO = gameObjectInfo._gameObject
	if targetGO then
		local meshRenderList = targetGO:GetComponentsInChildren(typeof(SkinnedMeshRenderer), true);
		for i = 0, meshRenderList.Length - 1 do
			local meshRender = meshRenderList[i]
			meshRender.enabled = isShow
		end

		local SpringManager = targetGO:GetComponent("SpringManager")
		if SpringManager then
			SpringManager.enabled = isShow
		end
	end
end

-- 切换显示名字板
CActor.ShowSwitchNamePnl = function(self, isShow)
	isShow = isShow and true or false
	if self._ui then
		self._ui:SetActive(isShow)
	end
	self._isUIShow = isShow
end

CActor.Show = function(self, isShow)
	self:ShowSwitch(isShow)
end

-- 切换显示, GO及 UI
CActor.ShowSwitch = function(self, isShow)
	self:ShowSwitchGo(isShow)
	self:ShowSwitchUi(isShow)
end

-- 切换显示Actor Go
CActor.ShowSwitchGo = function(self, isShow)
	self:ShowSwitchGameObject(isShow)
end

-- 切换显示Actor 头顶UI
CActor.ShowSwitchUi = function(self, isShow)
	self:ShowSwitchNamePnl(isShow)
end

-- 切换显示对象
CActor.ShowSwitchGameObject = function(self, isShow)
	local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)
	if gameObjectInfo then
		gameObjectInfo._gameObject:SetActive(isShow)
	end

	-- 显示/隐藏模型会重置动画状态机，要还原一下
	if isShow then
		self:RestoreAniState()
	end
	self._isShow = isShow
end

-- 冒泡说话, expandArgs:功能拓展参数
CActor.Say = function(self, content, durationTime, bgId, expandArgs, isFixed)
	local _, contentParsed = gGame:GetSpeechMgr():ParseAudioId(content)
	local objType = self:ToString()
	local sceneMgr = gGame:GetSceneMgr()
	local isFixed = isFixed
	if objType == "CPlayer" or objType == "CHero" then
		local npcData = gGame:GetDataMgr():GetNpcData()
		local isBubbleStory = npcData:GetBubbleChatStatus()
		local isSceneStory = sceneMgr:GetCurrentScene() and sceneMgr:GetCurrentScene()._isPlayingStory
		local isPlayingStory = isSceneStory or isBubbleStory
		local isFight = sceneMgr:isFightScene()
		if not isPlayingStory and not isFight then
			isFixed = true
		end
	end

	local canvas = nil
	if expandArgs and expandArgs['parentGo'] then
		canvas = expandArgs['parentGo']
	else
		canvas = gGame:GetUIMgr():GetSceneCanvasObj()
	end
	if not self._bubbleChat then
		self._bubbleChat = CBubbleChat:New(canvas)
	else
		self._bubbleChat:SetParentTr(canvas)
	end

	local offsetX = 0
	local offsetY = -0.8

	if not __UNITY_EDITOR__ then
		-- 保证 冒泡对话的时候，self._guaHp 不为空
		local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)
		self._guaHp = gameObjectInfo._gameObject.transform:Find("gua_hp")
		if not self._guaHp then
			self._guaHp = gameObjectInfo._gameObject.transform
		end
	end
	--assert(not tolua.isnull(self._guaHp), string.format("%s guaHp is null", self:GetName()))

	self._bubbleChat:SetFollowTarget(self._guaHp, offsetX, offsetY, canvas)

	-- 有时候出现GameCamera为空
	assert(Camera.main, string.format("缺少Camera.main"))
	self:SetBubbleFollowCamera(Camera.main)

	self._bubbleChat:Say(nil, contentParsed, durationTime, nil, bgId, expandArgs, isFixed)
end

-- 设置冒泡面板位置、底图、字体大小等信息
CActor.SetBubbleAttribute = function(self, fontSize, picPath, offsetX, offsetY )
	if fontSize > 0 then
		self._bubbleChat:SetFontSize(fontSize)
	end

	if picPath then
		self._bubbleChat:SetBGSprite(picPath)
	end

	offsetY = offsetY - 0.8
	self._bubbleChat:SetOffsetPos(offsetX, offsetY)
end

CActor.SetBubbleFollowCamera = function(self, gameCamera)
	self._bubbleChat:SetGameCamera(gameCamera)
end

CActor.StopSay = function(self)
	if self._bubbleChat then
		self._bubbleChat:Release()
		self._bubbleChat = nil
	end
end

-- 旋转到
CActor.RotateTo = function(self, targetObj, callBack)
	if tolua.isnull(targetObj) then return end
	self:DelRotateAI()
	if self:GetPosition() == targetObj.transform.position then return end
	local aiobject = gGame:GetAiMgr():CreateAI("actor_rotate", self )
	aiobject:SetData( "__target_obj", targetObj )
	aiobject:SetEndCallBack(function()
		self:DelRotateAI()

		if callBack then
			callBack()
		end
	end)
	gGame:GetAiMgr():TryRunAI(aiobject)
end

-- 旋转到具体方向
CActor.RotateToRotation = function(self, rotation)
	self:DelRotateAI()
	local aiobject = gGame:GetAiMgr():CreateAI("actor_rotate", self )
	aiobject:SetData( "__target_rotation", rotation )
	aiobject:SetEndCallBack(function()
		self:DelRotateAI()
	end)
	gGame:GetAiMgr():TryRunAI(aiobject)
end

-- 重置旋转
CActor.ResetRotate = function(self)
	self:RotateToRotation(self._originRotation)
end

CActor.DelRotateAI = function(self)
	gGame:GetAiMgr():CompleteActorAIByID(self, "actor_rotate")
end

-------------------------------------------------------------------------------------
-- Get Set Method
-------------------------------------------------------------------------------------
-- 设置GameObject名字
CActor.SetGoName = function (self, name)
	local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)
	gameObjectInfo:SetName(self._name)
end

-- 获得GameObject名字
CActor.GetGoName = function(self)
	local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)
	return gameObjectInfo:IsGoValid() and gameObjectInfo._gameObject.name
end

-- 获得名字，显示在头顶上的名字
CActor.GetName = function(self)
	return self._data["name"]
end

-- 获得称谓，显示在名字上面的称谓
CActor.GetTitle = function(self)
	return self._data["title"]
end

-- 设置UI跟随go
CActor.SetUiFollowTargetObj = function(self, targetObj)
	if self._uiFollowTargetObj then
		self._uiFollowTargetObj:SetTargetObj(targetObj)
	end
end

--播放Animator动画（设置Animator的state参数）
CActor.SetAniState = function (self, stateValue, isLoop, callBack, speed)
	if not stateValue then
		if callBack ~= nil then
			callBack()
		end
		return
	end

	self._aniState = stateValue

	speed = speed or self._speedAnim

	if isLoop == nil then
		isLoop = true
	end

	if self._animationAction then
		self:StopAction(self._animationAction)
		self._animationAction = nil
	end

	self._animationAction = AnimatorAction.Create()
	if callBack ~= nil then
		self._animationAction:SetArgs(self._aniState, CommonEnum.ANIMATOR_CONDITION_NAME, isLoop, callBack)
	else
		self._animationAction:SetArgs(self._aniState, CommonEnum.ANIMATOR_CONDITION_NAME, isLoop)
	end
	self._animationAction:SetSpeed(speed)

	self._animationAction:SetDestroyCallBackFunc(function()
		self._animationAction = nil
	end)

	self:RunAction(self._animationAction)
end

-- 恢复动画状态
CActor.RestoreAniState = function(self)
	local numState = tonumber(self._defaultAniState)
	if numState and numState == CommonEnum.STATE_DIE then
		self:DieInstant()
	else
		self:SetAniState(self._aniState)
	end
end

CActor.SetDefaultAniState = function(self, action)
	self._defaultAniState = action
end

--播放Animator动画（设置Animator的trigger参数）
CActor.SetAniTrigger = function(self, triggerName, hitCallBack)
	if not triggerName then
		return
	end

	local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)
	if not gameObjectInfo or not gameObjectInfo:IsGoValid() then return end

	if not self:GetGameObject().activeInHierarchy then return end

	local animator = gameObjectInfo._gameObject:GetComponent("Animator")
	if not animator then return end

	local animEventAdapter = gameObjectInfo._gameObject:GetComponent("AnimEventAdapter")
	if not animEventAdapter then
		animEventAdapter = UtilCommon.AddComponent(gameObjectInfo._gameObject, "AnimEventAdapter")
	end
	animEventAdapter:SetHitCallback(hitCallBack)
	animator:SetTrigger(triggerName)
end

-- 暂停/恢复Animator
CActor.SetAniPause = function(self, isPause)
	local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)
	if not gameObjectInfo:IsGoValid() then return end

	local cp = gameObjectInfo._gameObject:GetComponent("Animator")
	if not cp then return end

	local speed = 1
	if isPause then speed = 0 end
	cp.speed = speed
end

CActor.SetAniSpeed = function(self, speed)
	local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)
	if not gameObjectInfo:IsGoValid() then return end

	local cp = gameObjectInfo._gameObject:GetComponent("Animator")
	if not cp then return end
	cp.speed = speed
end

CActor.TrySetPose = function(self)
	local resid = self:GetResId()
	local resInfo = ALL_RES_ID[resid]

	if resInfo and resInfo["pose"] and resInfo["pose"] ~= "" then
		local poseInfo = string.split(resInfo["pose"], ":")
		self:SetPose(poseInfo[1], tonumber(poseInfo[2]))
	end

end

-- 摆模型pose, stateName:animation名称, normalizedTime:(0-1), 0表示动画开始位置, 1表示动画结束位置
CActor.SetPose = function(self, stateName, normalizedTime)
	if not stateName then return end
	normalizedTime = normalizedTime or 0

	local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)
	if not gameObjectInfo:IsGoValid() then return end
	local animator = gameObjectInfo._gameObject:GetComponent("Animator")
	if not animator then return end

	animator:Play(stateName, -1, normalizedTime)
	animator.speed = 0
	self._inPoseState = true
end

CActor.GetResId = function(self)
	return self._resid
end

CActor.IsLeavedOrDie = function(self)
	return self._isLeaved or self._isDie
end

-- 添加状态
CActor.AddStatus = function (self, status, params, isCacheStatus)
	if not status then return end
	params = params or {}

	local st = {}
	st["status"] = status
	st["params"] = params
	st["isCacheStatus"] = isCacheStatus or false

	self._status[status] = st

	if (not isCacheStatus) then
		self:ShowStatus(st)
	end

	return status
end

-- 缓存状态，如冰封
CActor.ShowCachedStatus = function(self)
	for _, st in pairs(self._status) do
		if st.isCacheStatus then
			st.isCacheStatus = false
			self:ShowStatus(st)
		end
	end
end

-- 显示状态信息
CActor.ShowStatus = function(self, statusInfo)
	local status = statusInfo.status
	local params = statusInfo.params
	-- 特效对象
	local effectGOs, plugName = self:SetStatusEffect(status, false)
	if effectGOs then
		statusInfo["effect_gos"] = effectGOs
	end

	statusInfo["plugName"] = plugName
	statusInfo["idx"] = self:GetStatusIdxByPlug(plugName)

	self:DestroyStatusEffect(plugName)

	if params.aniState then
		self:SetAniState(params.aniState, params.aniStateLoop, params.aniStateFinishCallBack)
	end
	-- if params.prefab then
		-- self:CreateEffectGameObject("gua_effect_foot", params.prefab, true)
		-- local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)
		-- SkillPlayer.Instance():Play(params.prefab, {gameObjectInfo._gameObject}, {})
	if params.aniTrigger then
		self:SetAniTrigger(params.aniTrigger, params.aniTriggerEventCallBack)
	end

	-- 暂停播放动画
	if params.aniPause then
		-- 冰封状态, 把Animator的动画播放速度降为0
		self:SetAniPause(true)
	end
end

-- 状态中存了状态值
CActor.GetStatus = function (self, status)
	if not status then return end
	return self._status[status]
end

CActor.GetAllStatus = function(self)
	return self._status
end

-- 移除所有状态特效
CActor.RemoveAllStatus = function(self)
		local statusList = {}
		for status, _ in pairs(self._status) do
			table.insert(statusList, status)
		end

		for _, status in ipairs(statusList) do
			self:RemoveStatus(status)
		end
end

-- 移除状态
CActor.RemoveStatus = function (self, status)
	if not status or not self._status[status] then
		return
	end

	if self._status[status]["effect_gos"] then
		for k,v in pairs(self._status[status]["effect_gos"]) do
			if not tolua.isnull(v) then
				GameObject.Destroy(v)
			end
		end
	end

	self:SetStatusEffect(status, true)

	self._status[status] = nil
end

-- 是否在状态中
CActor.InStatus = function (self, status)
	return self._status[status]
end

--[[
-- 同个挂点上的状态特效最多显示3个
-- 该状态有特效，该状态对应挂点上的状态特效少于三个
CActor.CanShowStatus = function(self, status)
	local canShowStatus = true
	local statusConfig = CFightStatusData:Get(status)
	if statusConfig and statusConfig["effect"] then
		local plugName = statusConfig["effect"][1]

		local effectCntOnPlug = 0
		for status, statusInfo in pairs(self._status) do
			if statusInfo.show and statusInfo.plugName == plugName then
				effectCntOnPlug = effectCntOnPlug + 1
			end
		end

		local MAX_EFFECT_CNT_ON_PLUG = 3
		if effectCntOnPlug >= MAX_EFFECT_CNT_ON_PLUG then
			canShowStatus = false
		end
	end
	return canShowStatus
end
]]--

CActor.Idle = function (self)
	local numState = tonumber(self._defaultAniState)
	if numState and numState == CommonEnum.STATE_DIE then
		self:DieInstant()
		return
	end
	if numState then
		self:SetAniState(numState)
	else
		self:SetAniTrigger(self._defaultAniState, function() end)
	end
end

CActor.Die = function (self)
	self._isDie = true
	self:SetAniState(CommonEnum.STATE_DIE, false)
end

CActor.DieInstant = function (self)
	self._isDie = true
	self:SetAniState(CommonEnum.STATE_DIE, false, nil, 1000)
end

-- 创建特效对象
CActor.SetStatusEffect = function (self, status, isEnd)

	local props = CFightStatusData:Get(status)
	if props == nil then return nil end

	local isFollow = props.notFollow == nil
	local res = {}
	local plugName, prefabPath, go

	if not isEnd then
		-- 开始特效
		if props["begin_effect"] then
			plugName = props["begin_effect"][1]
			prefabPath = self:GetEffectPrefabPath(props["begin_effect"][2])
			go = self:CreateEffectGameObject(plugName, prefabPath, isFollow)
			res["begin_effect"] = go
		end

		-- 持续特效
		if props["effect"] then
			plugName = props["effect"][1]
			prefabPath = self:GetEffectPrefabPath(props["effect"][2])
			go = self:CreateEffectGameObject(plugName, prefabPath, isFollow)
			res["effect"] = go
		end
	else
		-- 结束特效
		if props["end_effect"] then
			plugName = props["end_effect"][1]
			prefabPath = self:GetEffectPrefabPath(props["end_effect"][2])
			go = self:CreateEffectGameObject(plugName, prefabPath, isFollow)
			res["end_effect"] = go
			--error("查找结束特效错误BUG")
		end
	end

	return res, plugName
end

local findTargetGOInGameObjectChild = function( root, name )
	local imageComs = root:GetComponentsInChildren(typeof(Transform), true)
	for i = 0, imageComs.Length - 1 do
		local childTran = imageComs[i]

		if childTran.name == name then return childTran.gameObject end
	end
end

-- 创建特效的GO
CActor.CreateEffectGameObject = function (self, plugName, prefabPath, isFollow)
	if self:GetGameObject() == nil then
		print("创建特效时, 玩家自己的GameObject为空")
		assert(false, "创建特效时, 玩家自己的GameObject为空, prefabPath"..prefabPath)
		Logger.error(traceback())
	end

	-- 特效go
	local go = Tool.Instantiate(prefabPath)

	local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)
	-- 状态挂接点
	if not plugName or plugName == "" then
		go.transform.position = gameObjectInfo._gameObject.transform.position
		go.transform.rotation = gameObjectInfo._gameObject.transform.rotation
	else
		local goPlug = gameObjectInfo._gameObject.transform:Find(plugName)

		if not goPlug and self._namePnl and self._namePnl._goHp then
			goPlug = self._namePnl._goHp.transform:Find(plugName)
		end

		--assert(goPlug, "DO NOT have plug Object:"..plugName)
		if (not goPlug) then
			goPlug = findTargetGOInGameObjectChild( gameObjectInfo._gameObject, plugName )
			print("goPlug:", gameObjectInfo._gameObject.name, plugName)

			-- 找不到挂点则选择gua_middle挂点
			if (not goPlug) then
				goPlug = gameObjectInfo._gameObject.transform:Find("gua_middle")
			end
			assert(goPlug, "DO NOT have plug Object:"..plugName)
		end

		go.transform:SetParent(goPlug.transform, false)
		if not isFollow then
			go.transform:SetParent(nil, true)
		end
	end
	return go
end

CActor.GetStatusIdxByPlug = function(self, plugName)
	local statusIdx = 0

	for _, status in pairs(self._status) do 
		status["idx"] = status["idx"] or 1
		if status["plugName"] == plugName and status["idx"] > statusIdx then 
			statusIdx = status["idx"]
		end 
	end 

	return statusIdx + 1
end 

-- 如果一个挂点上有超过3个特效，则只保留最新的3个状态的特效
CActor.DestroyStatusEffect = function(self, plugName)
	local minIdx = 999999
	local deleteEffect = false 
	local effectCntOnPlug = 0
	local toDestroyEffectObjStatus = nil

	for _, status in pairs(self._status) do 
		if not status.effectDestroyed then 
			if (status["plugName"] == plugName) then 
				effectCntOnPlug = effectCntOnPlug + 1

				if (status["idx"] < minIdx) then 
					minIdx = status["idx"]
					toDestroyEffectObjStatus = status
				end 
			end 
		end 
	end 

	local MAX_EFFECT_CNT_ON_PLUG = 3

	if effectCntOnPlug > MAX_EFFECT_CNT_ON_PLUG then 
		local toDeleteEffectObj = toDestroyEffectObjStatus["effect_gos"] or {}
		toDestroyEffectObjStatus.effectDestroyed = true
		for _, go in pairs(toDeleteEffectObj) do 
			if not tolua.isnull(go) then 
				GameObject.Destroy(go)
			end 
		end 
	end 
end 

CActor.GetEffectPrefabPath = function (self, name)
	return "Assets/res/Effects/e_buff/"..tostring(name)
end

CActor.GetAniState = function(self)
	return self._aniState
end

CActor.SetArea = function (self, area)
	self._area = area
end

CActor.GetArea = function(self)
	return self._area
end

CActor.SetLayer = function (self, layerName)
	local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)
	gameObjectInfo:SetLayerName(layerName)
end

-- 设置名字颜色
CActor.SetNameTxtColor = function(self, color)
	if not color then return end
	if IsNull(self._ui) or IsNull(self._ui._nameText) then return end
	self._ui._nameText.color = color
end

-------------------------------------------------------------------------------------
-- 只有获得方法
-------------------------------------------------------------------------------------
CActor.GetGameObjectUID = function(self)
	return self._gameobjectUID
end

CActor.GetGameObject = function(self)
	local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)
	if not gameObjectInfo then return end
	return gameObjectInfo._gameObject
end

CActor.GetUi = function(self)
	return self._ui
end

CActor.GetGuaHp = function(self)
	if not self._guaHp then
		self._guaHp = self:GetGameObject().transform:Find("gua_hp")

		if not self._guaHp then
			self._guaHp = self:GetGameObject().transform
		end
	end

	return self._guaHp
end

CActor.GetMainPrefabPath = function(self)
	return self._mainPrefabPath or ""
end

CActor.GetData = function(self)
	return self._data
end

CActor.GetId = function(self)
	return self._id
end

CActor.SetId = function(self, id)
	self._id = id
end

CActor.SetOrgId = function(self, orgId)
	self._orgId = orgId
end

CActor.GetOrgId = function(self, orgId)
	return self._orgId
end

CActor.GetType = function (self)
	return self._type
end

CActor.IsHero = function(self)
	return self._isHero
end

CActor.IsOrgFightObj = function(self)
	return false
end

CActor.GetEquipType = function(self)
	return self._equipTypes
end

-- 设置位置
CActor.SetPosition = function(self, pos, derive)
	local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)
	if gameObjectInfo then
		if derive then
			gameObjectInfo._gameObject.transform.position = Vector3.New(pos.x or 0, pos.y or 0, pos.z or 0)

		else
			gameObjectInfo._gameObject.transform.localPosition = Vector3.New(pos.x or 0, pos.y or 0, pos.z or 0)
		end
	end
end

CActor.GetPosition = function(self, derive)
	local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)
	if gameObjectInfo then
		if tolua.isnull(gameObjectInfo._gameObject) then
			return
		end
		return derive and gameObjectInfo._gameObject.transform.position or gameObjectInfo._gameObject.transform.localPosition
	else
		return Vector3.New(0, 0, 0)
	end
end

CActor.SetRotation = function(self, rot, isTotally)
	local r = Vector3.New(rot.x or 0, rot.y or 0, rot.z or 0)
	local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)
	if gameObjectInfo:IsGoValid() then
		gameObjectInfo._gameObject.transform.localEulerAngles = r
	end
	if isTotally and self._basePlateObj.transform then
		self._basePlateObj.transform.localEulerAngles = r
	end
end

CActor.GetRotation = function(self)
	local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)
	if gameObjectInfo:IsGoValid() then
		return gameObjectInfo._gameObject.transform.localEulerAngles
	else
		return Vector3.New(0, 0, 0)
	end
end

-- 设置模型默认缩放大小，#38311提出NPC、主角、灵兽有一个整体默认缩放系数
CActor.SetDefaultModelScale = function(self, scale)
	if not scale then return end
	self._defaultScale = scale
	self:SetScale(scale)
end

CActor.SetScale = function(self, scale)
	local s
	if type(scale) == "table" then
		s = Vector3.New(scale.x or 1, scale.y or 1, scale.z or 1)
	else
		local mScale = scale or 1
		s = Vector3.New(mScale, mScale, mScale)
	end
	local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)
	gameObjectInfo._gameObject.transform.localScale = s
end

CActor.GetScale = function(self)
	local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)
	if gameObjectInfo:IsGoValid() then
		return gameObjectInfo._gameObject.transform.localScale
	else
		return Vector3.New(1, 1, 1)
	end
end

-- isOffsetCenter:主要是考虑包围盒中心偏移，这里加上了中心的z则是计算包围盒中心点到包围盒边缘的距离
CActor.GetRadius = function(self, isOffsetCenter)
	local cc = self:GetComponent("CapsuleCollider")
	local goRadius = 0
	if ( cc ) then
		goRadius = cc.radius
		if isOffsetCenter then
			goRadius = goRadius + cc.center.z
		end
	end
	local scale = self:GetScale().x
	return goRadius * scale
end

CActor.SetColliderRadius = function(self, radius)
	local cc = self:GetComponent("CapsuleCollider")
	if cc and radius then
		cc.radius = radius
	end
end

--这里居然实现了多次添脚本不重复的功能 Lorry
CActor.AddComponent = function(self, com_name)
	local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)
	if not gameObjectInfo:IsGoValid() then return end

	local com = UtilCommon.GetComponent(gameObjectInfo._gameObject, com_name)
	if com then
		return
	else
		UtilCommon.AddComponent(gameObjectInfo._gameObject, com_name)
	end
end

--获取组件
CActor.GetComponent = function(self, comName)
	local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)
	if not gameObjectInfo:IsGoValid() then return end

	local com = UtilCommon.GetComponent(gameObjectInfo._gameObject, comName)
	return com
end

--移除组件
CActor.RemoveComponent = function(self, com_name)
	local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)
	if not gameObjectInfo:IsGoValid() then return end
	local com = gameObjectInfo._gameObject:GetComponent(com_name)
	if not com then return end
	GameObject.Destroy(com)
end

CActor.ToString = function(self)
	return "CActor"
end

CActor.SetOwner = function(self, owner)
	self._owner = owner
	local followPos = self:GetFollowPos()
	local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)
	gameObjectInfo._gameObject.transform.position = Vector3(followPos.x, followPos.y, followPos.z)
	local ownerPos = self._owner:GetPosition(true)
	ownerPos.y = followPos.y
	gameObjectInfo._gameObject.transform:LookAt(ownerPos)
end

-- 获得主人身后的位置
CActor.GetFollowPos = function(self)
	local heroRadius = 5	-- 默认范围
	local cpCapsuleCollider = self._owner:GetComponent("CapsuleCollider")
	if cpCapsuleCollider then heroRadius = cpCapsuleCollider.radius end

	local summonRadius = 0.5 -- 宠物大小范围 --self:GetComponent("SphereCollider").radius
	local heroPos = self._owner:GetPosition(true)
	local hasRayCast, rayCastHeight = CommonUtil.GetServerHeightByRayCast(heroPos.x, heroPos.z, CommonEnum.AREA_GROUND)
	local heroBackDir = -self._owner:GetGameObject().transform.forward
	local heroBackDirNormal = heroBackDir:Normalize()
	local summonPos = heroPos + heroBackDirNormal * (heroRadius + summonRadius)
	summonPos.y = rayCastHeight
	return summonPos
end

CActor.Update = function(self)
	local gameObjectInfo = gGame:GetGameObjectMgr():GetGameObjectInfo(self._gameobjectUID)
	if gameObjectInfo:IsGoValid() and self._owner ~= nil then
		local dist = Vector3.Distance(self._owner:GetPosition(true), self:GetPosition(true))
		if dist >= self._maxDist then
			self:RunToPos(self:GetFollowPos())
		end
	end
end

--心跳
CActor.HeartBeat = function(self, dt)
	-- AI更新
	self:UpdateAI(dt)
end

CActor.PosCheck = function(self)
	self._curWorldPos = self:GetPosition(true)
	if math.abs(self._curWorldPos.x - self._preWorldPos.x) >= self._posChangeFlag or
		math.abs(self._curWorldPos.y - self._preWorldPos.y) >= self._posChangeFlag or
		math.abs(self._curWorldPos.z - self._preWorldPos.z) >= self._posChangeFlag then
		self:OnPosChangeCallBack()
		self._preWorldPos = self._curWorldPos
	end
end

-------------------------------------------------------------------------------------
-- AI有关函数
-------------------------------------------------------------------------------------
-- AI更新
CActor.UpdateAI = function (self, dt)

	gGame:GetAiMgr():UpdateAI(self, dt)

	-- 策略
	--self:TryOpportunity(AI_OPPORTUNITY.TACTIC, {})
end

-- AI释放
CActor.AIRelease = function(self)
	gGame:GetAiMgr():CompleteActorAI(self)
end


-------------------------------------------------------------------------------------
-- 销毁方法
-------------------------------------------------------------------------------------
-- 释放UI
CActor.ReleaseUI = function (self)

	if not tolua.isnull(self._ui) then
		GameObject.Destroy(self._ui)
	end

	self._ui = nil

	if self._uiFollowTargetObj then
		self._uiFollowTargetObj:Release()
		self._uiFollowTargetObj = nil
	end
end

-- 释放go
CActor.ReleaseGameObject = function(self)
	self:StopAllAction()
	gGame:GetGameObjectMgr():RemoveGameObjectInfo(self._gameobjectUID)
end

--销毁常驻特效
CActor.ReleasePermanentEffects = function(self)
	for _, go in ipairs(self._permanentEffectGos) do
		GameObject.Destroy(go)
	end
	self._permanentEffectGos = {}
end

-- 释放事件监听器
CActor.ReleaseListener = function(self)
	for path, timer in pairs(self._effectDelayTimer) do
		self:ReleaseEffectDelayTimer(path)
	end

	for path, timer in pairs(self._effectLastTimer) do
		self:ReleaseEffectLastTimer(path)
	end
end

CActor.ReleaseEffectDelayTimer = function(self, effectPath)
	if not self._effectDelayTimer[effectPath] then return end

	gGame:GetTimeManager():RemoveTimer(self._effectDelayTimer[effectPath])
	self._effectDelayTimer[effectPath] = nil
end

CActor.ReleaseEffectLastTimer = function(self, effectPath)
	if not self._effectLastTimer[effectPath] then return end

	gGame:GetTimeManager():RemoveTimer(self._effectLastTimer[effectPath])
	self._effectLastTimer[effectPath] = nil
end

-- 释放实体
CActor.ReleaseEntry = function(self)
	self:ReleaseUI()
	self:ReleaseGameObject() --如果子类有这个方法调用子类的
end

-- 释放
CActor.Release = function(self)
	self:ReleaseListener()
	self:AIRelease()
	self:ReleaseEntry()
	self:ReleaseAllObjEffect()
	self:ReleasePermanentEffects()
	if self._bubbleChat then
		self._bubbleChat:Release()
		self._bubbleChat = nil
	end

	self:StopAction(self._searchToAction)
	self._searchToAction = nil

	self:StopAction(self._animationAction)
	self._animationAction = nil

	self._stopSearchCb = nil
end

-- 销毁
CActor.Destroy = function(self)
	self._isDie = true
	self:ClearItemObjList()
	self:UnSelect()
	self:RemoveAllStatus()
	self:Release()
	CObjectBase.OnDestroy(self)
end